﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using NLog;

namespace SellAvi.Classes
{
    public class WebClientEx : WebClient
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        public event EventHandler HtmlChanged;

        public WebHeaderCollection DefaultHeaders { get; set; }

        public Uri ResponseUri
        {
            get { return _responseUri; }
            set { _responseUri = value; }
        }
        private string _responseHtml;
        private Uri _responseUri = new Uri("https://www.avito.ru/");

        public string ResponseHtml
        {
            get { return _responseHtml; }
            set
            {
                _responseHtml = value;
                OnHtmlChanged();
            }
        }

        public WebClientEx(CookieContainer container)
        {
            this.CookieContainer = container;
        }
        public WebClientEx()
        {
            this.DefaultHeaders = new WebHeaderCollection();
            this.CookieContainer = new CookieContainer();
        }

        public CookieContainer CookieContainer { get; set; }

        /// <summary>
        ///  CookieContainer.SetCookies(new Uri("https://www.avito.ru"),response.Headers[HttpResponseHeader.SetCookie]);
        /// </summary>
        /// <param name="cookieString"></param>
        /// <param name="url"></param>
        public void FillCookieContainer(string cookieString, string url)
        {
            // 1.
            //foreach (var cookieElement in cookieString.Split(';'))
            //{
            //    CookieContainer.SetCookies(new Uri(url), cookieElement.Trim());
            //}

            // 2.
            //http://stackoverflow.com/questions/1047669/cookiecontainer-bug
            //CookieContainer.SetCookies(new Uri(url), cookieString.Replace(";", ","));

            // 3.
            foreach (var cookieElement in cookieString.Split(';'))
            {
                var cName = cookieElement.Split('=')[0].Trim();
                var cValue = cookieElement.Split('=')[1].Trim();
                CookieContainer.Add(new Cookie(cName, cValue, "/", ".avito.ru"));
            }
        }

        public new string UploadValues(Uri address, NameValueCollection nvc)
        {
            byte[] r = base.UploadValues(address, nvc);
            return _responseHtml = Encoding.GetString(r);
        }

        public new string DownloadString(Uri address)
        {
            return _responseHtml = base.DownloadString(address);
        }

        public new string UploadString(Uri address, string data)
        {
            return _responseHtml = base.UploadString(address, data);
        }

        public string DownloadStringWithNotification(Uri address)
        {
            ResponseHtml = DownloadString(address);
            return ResponseHtml;
        }
        public void OnHtmlChanged()
        {
            if (HtmlChanged != null)
            {
                HtmlChanged(this, EventArgs.Empty);
            }
        }

        public void BrowserNavigationNeeded(Uri urlTo)
        {
            if (HtmlChanged != null)
            {
                HtmlChanged(this, new NavigationEventArgs(){NavigateTo = urlTo});
            }
        }

        protected override WebRequest GetWebRequest(Uri address)
        {
            WebRequest r = base.GetWebRequest(address);
            var request = r as HttpWebRequest;
            if (request != null)
            {
                // Важна последовательность заголовков!
                request.Accept = DefaultHeaders[HttpRequestHeader.Accept];
                request.Referer = DefaultHeaders[HttpRequestHeader.Referer] ?? ResponseUri.ToString();
                request.ContentType = DefaultHeaders[HttpRequestHeader.ContentType];
                request.UserAgent = DefaultHeaders[HttpRequestHeader.UserAgent];
                request.CookieContainer = CookieContainer;

            }
            return r;


        }

        protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
        {
            try
            {
                WebResponse response = base.GetWebResponse(request, result);
                //ReadHtmlContent(response); //BUG: не задействовать метод поскольку он закрывает соедиение
                ReadCookies(response);
                ReadResponseUri(response);
                return response;
            }
            catch (Exception ex)
            {
                Logger.Error("Запрос страницы {0} завершился с ошибкой >> {1}", request.RequestUri, ex.Message);
            }
            return null;
        }

        protected override WebResponse GetWebResponse(WebRequest request)
        {
            try
            {
                WebResponse response = base.GetWebResponse(request);
                //ReadHtmlContent(response);
                ReadResponseUri(response);
                ReadCookies(response);
                return response;
            }
            catch (Exception ex)
            {
                Logger.Error("Запрос страницы {0} завершился с ошибкой >> {1}", request.RequestUri, ex.Message);
            }
            return null;

        }

        private void ReadCookies(WebResponse r)
        {
            var response = r as HttpWebResponse;
            if (response != null)
            {
                CookieCollection cookies = response.Cookies;
                CookieContainer.Add(cookies);
                //OR
                //CookieContainer.SetCookies(new Uri("https://www.avito.ru"), response.Headers[HttpResponseHeader.SetCookie]);
            }
        }

        private void ReadHtmlContent(WebResponse r)
        {
            var response = r as HttpWebResponse;
            if (response != null)
            {
                using (var reader = new StreamReader(response.GetResponseStream()))
                {
                    ResponseHtml = reader.ReadToEnd();
                }
            }
        }
        private void ReadResponseUri(WebResponse r)
        {
            var response = r as HttpWebResponse;
            if (response != null)
            {
                ResponseUri = response.ResponseUri;
            }
        }
        public class NavigationEventArgs : EventArgs
        {
            public Uri NavigateTo { get; set; }
        }
    }
}